home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Palettes / MiscDatePalette / MiscDateView.subproj / MiscDateView.m < prev    next >
Encoding:
Text File  |  1995-07-06  |  10.6 KB  |  517 lines

  1. //
  2. //    MiscDateView.m -- a view for dealing with input and display of dates
  3. //        Written by Hugh Ashton, Copyright (c) 1994 by Hugh Ashton.
  4. //                Version 1.0  All rights reserved.
  5. //        This notice may not be removed from this source code.
  6. //
  7. //    This object is included in the MiscKit by permission from the author
  8. //    and its use is governed by the MiscKit license, found in the file
  9. //    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  10. //    for a list of all applicable permissions and restrictions.
  11. //    
  12.  
  13. #include <time.h>
  14. #include <libc.h>
  15. #include <strings.h>
  16. #import "MiscDateView.h"
  17.  
  18. #define CURRENT_VERSION 1
  19.  
  20. id    BundleForStrings = nil;
  21.  
  22. #define MONDAY NXLocalizedStringFromTableInBundle (NULL,BundleForStrings,"Monday",NULL,zeroth day of week)
  23. #define TUESDAY NXLocalizedStringFromTableInBundle (NULL,BundleForStrings,"Tuesday",NULL,first day of week)
  24. #define WEDNESDAY NXLocalizedStringFromTableInBundle (NULL,BundleForStrings,"Wednesday",NULL,second day of week)
  25. #define THURSDAY NXLocalizedStringFromTableInBundle (NULL,BundleForStrings,"Thursday",NULL,third day of week)
  26. #define FRIDAY NXLocalizedStringFromTableInBundle (NULL,BundleForStrings,"Fri",NULL,fourth day of week)
  27. #define SATURDAY NXLocalizedStringFromTableInBundle (NULL,BundleForStrings,"Sat",NULL,fifth day of week)
  28. #define SUNDAY NXLocalizedStringFromTableInBundle (NULL,BundleForStrings,"Sun",NULL,sixth day of week)
  29. #define DATE_ERROR NXLocalizedStringFromTableInBundle (NULL,BundleForStrings,"Date entry error",NULL,error in date entry)
  30.  
  31. @implementation MiscDateView
  32.  
  33. + initialize
  34. {
  35.     if ( self == [MiscDateView class] )
  36.         [MiscDateView setVersion:CURRENT_VERSION];
  37.  
  38.     return self;
  39. }
  40.  
  41. - decDay:sender
  42. {
  43.     int mm;
  44.     
  45.     if(strlen([day stringValue])>0)
  46.     {
  47.         [day setIntValue:[day intValue]-1];
  48.     }
  49.     if([day intValue]<1)
  50.     {
  51.         [month setIntValue:[month intValue]-1];
  52.         if([month intValue]<1)
  53.         {
  54.             [month setIntValue:12];
  55.             [year setIntValue:[year intValue]-1];
  56.         }
  57.         mm=[month intValue];
  58.         if(mm==4 || mm==6 || mm==9 || mm==11)
  59. /*
  60.     30 days hath September...
  61. */        {
  62.             [day setIntValue:30];
  63.             [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  64.             return self;
  65.         }
  66.         if(mm==2)
  67.         {
  68.             if([self isItaLeapYear:[year intValue]])
  69. /*
  70. leap year
  71. */
  72.             {
  73.                 [day setIntValue:29];
  74.             }
  75.             else
  76.             {
  77.                 [day setIntValue:28];
  78.             }
  79.             [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  80.             return self;
  81.         }
  82.         [day setIntValue:31];
  83.     }
  84.     [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  85.     [self isDateValid:self];
  86.                 
  87.     return self;
  88. }
  89.  
  90. - decMonth:sender
  91. {
  92.     if(strlen([month stringValue])>0)
  93.     {
  94.         [month setIntValue:[month intValue]-1];
  95.     }
  96.     if([month intValue]<1)
  97.     {
  98.         [month setIntValue:12];
  99.         [year setIntValue:[year intValue]-1];
  100.     }
  101.     [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  102.     [self isDateValid:self];
  103.     return self;
  104. }
  105.  
  106. - outputDOW:(unsigned int)number
  107. {
  108.     number=number%7;
  109.     
  110.     if(number==0)
  111.     {
  112.         [dow setStringValue:MONDAY];
  113.         return self;
  114.     }
  115.     if(number==1)
  116.     {
  117.         [dow setStringValue:TUESDAY];
  118.         return self;
  119.     }
  120.     if(number==2)
  121.     {
  122.         [dow setStringValue:WEDNESDAY];
  123.         return self;
  124.     }
  125.     if(number==3)
  126.     {
  127.         [dow setStringValue:THURSDAY];
  128.         return self;
  129.     }
  130.     if(number==4)
  131.     {
  132.         [dow setStringValue:FRIDAY];
  133.         return self;
  134.     }
  135.     if(number==5)
  136.     {
  137.         [dow setStringValue:SATURDAY];
  138.         return self;
  139.     }
  140.     if(number==6)
  141.     {
  142.         [dow setStringValue:SUNDAY];
  143.         return self;
  144.     }
  145.     return self;
  146. }
  147.     
  148. - decYear:sender
  149. {
  150.     if(strlen([year stringValue])>0)
  151.     {
  152.         [year setIntValue:[year intValue]-1];
  153.     }
  154.     [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  155.     [self isDateValid:self];
  156.     return self;
  157. }
  158.  
  159. - checkDay:sender
  160. {
  161.     if((strlen([day stringValue])==0) || (strlen([month  stringValue])==0) || (strlen([year stringValue])==0))
  162.     {
  163.         [dow setStringValue:"XXX"];
  164.         return self;
  165.     }
  166.     [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  167.     [self isDateValid:self];
  168.     return self;
  169. }
  170. - (unsigned int)whatDayIs:(int)theDay :(int)theMonth :(int)theYear
  171. /*
  172.     we take 1 January 1901 as our base
  173.     Mon=0, Tue=1, etc
  174. */
  175. {
  176.     unsigned int i;
  177.     unsigned int current_count;
  178.     current_count=1;
  179. /*
  180.     as it happens, 1/1/1901 was a Tuesday
  181. */
  182.     if(theYear<1901)
  183.     {
  184.         return 00;
  185.     }
  186.     for(i=1901;i<theYear;i++)
  187.     {
  188.         if([self isItaLeapYear:i])
  189.         {
  190.             current_count=(current_count+=366);
  191.         }
  192.         else
  193.         {
  194.             current_count=(current_count+=365);
  195.         }
  196.     }
  197.     for(i=1;i<theMonth;i++)
  198.     {
  199.         if((i==4) || (i==6) || (i==9) || (i==11))
  200.         {
  201.             current_count+=30;
  202.         }
  203.         if((i==2) && ([self isItaLeapYear:theYear]))
  204.         {
  205.             current_count+=29;
  206.         }
  207.         if((i==2) && (![self isItaLeapYear:theYear]))
  208.         {
  209.             current_count+=28;
  210.         }
  211.         if((i==1) || (i==3) || (i==5) || (i==7) || (i==8) || (i==10) || (i==12))
  212.         {
  213.             current_count+=31;
  214.         }
  215.     }
  216.     for(i=1;i<theDay;i++)
  217.     {
  218.         current_count+=1;
  219.     }
  220.     
  221. /*
  222.     fencepost error, hence this kludge
  223.     current_count=current_count-1;
  224. */
  225.     return current_count;
  226. }
  227. - (BOOL)isItaLeapYear:(int)theYear
  228. {
  229.     // Fix from Rod Ragner:
  230.     return ((!(theYear % 4) && (theYear % 200)) ? YES : NO);
  231. // old way is incorrect:
  232. //    if((theYear/4.0)==(theYear/4))
  233. //    {
  234. //        return YES;
  235. //    }
  236. //    else
  237. //    {
  238. //        return NO;
  239. //    }
  240. }
  241. - getTodaysDate:sender
  242. {
  243.     long currenttime;
  244.     char dateString[60]="";
  245.     int dd;
  246.     int mm=0;
  247.     char mmStr[4]="";
  248.     int yyyy;
  249.     char dowStr[4]="";
  250.     char timeString[20]="";
  251.  
  252.     currenttime = time(0L);
  253.     strcpy(dateString,ctime(¤ttime));
  254.     
  255.     sscanf(dateString,"%s %s %d %s %d",dowStr,mmStr,&dd,timeString,&yyyy);
  256.     [dow setStringValue:dowStr];
  257.     [year setIntValue:yyyy];
  258.     [day setIntValue:dd];
  259.     if(strcmp(mmStr,"Jan")==0)
  260.     {
  261.         mm=1;
  262.     }
  263.     if((strcmp(mmStr,"Feb"))==0)
  264.     {
  265.         mm=2;
  266.     }
  267.     if((strcmp(mmStr,"Mar"))==0)
  268.     {
  269.         mm=3;
  270.     }
  271.     if((strcmp(mmStr,"Apr"))==0)
  272.     {
  273.         mm=4;
  274.     }
  275.     if((strcmp(mmStr,"May"))==0)
  276.     {
  277.         mm=5;
  278.     }
  279.     if((strcmp(mmStr,"Jun"))==0)
  280.     {
  281.         mm=6;
  282.     }
  283.     if((strcmp(mmStr,"Jul"))==0)
  284.     {
  285.         mm=7;
  286.     }
  287.     if((strcmp(mmStr,"Aug"))==0)
  288.     {
  289.         mm=8;
  290.     }
  291.     if((strcmp(mmStr,"Sep"))==0)
  292.     {
  293.         mm=9;
  294.     }
  295.     if((strcmp(mmStr,"Oct"))==0)
  296.     {
  297.         mm=10;
  298.     }
  299.     if((strcmp(mmStr,"Nov"))==0)
  300.     {
  301.         mm=11;
  302.     }
  303.     if((strcmp(mmStr,"Dec"))==0)
  304.     {
  305.         mm=12;
  306.     }
  307.     [month setIntValue:mm];
  308.     return self;
  309. }
  310.  
  311. - incDay:sender
  312. {
  313.     int mm=0;
  314.     
  315.     mm=[month intValue];
  316.     
  317.     if(strlen([day stringValue])>0)
  318.     {
  319.         [day setIntValue:[day intValue]+1];
  320.     }
  321.     if((mm==4 || mm==6 || mm==9 || mm==11) && [day intValue]>30)
  322.     {
  323.         [month setIntValue:[month intValue]+1];
  324.         [day setIntValue:1];
  325.         [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  326.         return self;
  327.     }
  328.     if((mm==2) && ([day intValue]>28) && (![self isItaLeapYear:[year intValue]]))
  329.     {
  330.         [month setIntValue:3];
  331.         [day setIntValue:1];
  332.         [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  333.         return self;
  334.     }
  335.     if((mm==2) && ([day intValue]>29) && ([self isItaLeapYear:[year intValue]]))
  336.     {
  337.         [month setIntValue:3];
  338.         [day setIntValue:1];
  339.         [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  340.         return self;
  341.     }
  342.     
  343.     if([day intValue]>31)
  344.     {
  345.         [month setIntValue:[month intValue]+1];
  346.         [day setIntValue:1];
  347.         if([month intValue]>12)
  348.         {
  349.             [month setIntValue:1];
  350.             [year setIntValue:[year intValue]+1];
  351.         }
  352.     }
  353.     [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  354.     [self isDateValid:self];
  355.     return self;
  356. }
  357.  
  358. - incMonth:sender
  359. {
  360.     if(strlen([month stringValue])>0)
  361.     {
  362.         [month setIntValue:[month intValue]+1];
  363.     }
  364.     if([month intValue]>12)
  365.     {
  366.         [month setIntValue:1];
  367.         [year setIntValue:[year intValue]+1];
  368.     }
  369.     [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  370.     [self isDateValid:self];
  371.     return self;
  372. }
  373.  
  374. - incYear:sender
  375. {
  376.     if(strlen([year stringValue])>0)
  377.     {
  378.         [year setIntValue:[year intValue]+1];
  379.     }
  380.     [self outputDOW:[self whatDayIs:[day intValue] :[month intValue] : [year intValue]]];
  381.     [self isDateValid:self];
  382.     return self;
  383. }
  384.  
  385. - (BOOL)isDateValid:sender
  386. {
  387.     if(([year intValue]>2050) || ([year intValue]<1901))
  388.     {
  389.         NXRunAlertPanel(DATE_ERROR,"Year is outside range 1901 to 2050","OK",NULL,NULL);
  390.         [year selectText:self];
  391.         [dow setStringValue:"XXX"];
  392.         return NO;
  393.     }
  394.     if(([month intValue]>12) || ([month intValue]<1))
  395.     {
  396.         NXRunAlertPanel(DATE_ERROR,"Month is outside range 1 to 12","OK",NULL,NULL);
  397.         [month selectText:self];
  398.         [dow setStringValue:"XXX"];
  399.         return NO;
  400.     }
  401.     if(([day intValue]<1) || ([day intValue]>31))
  402.     {
  403.         NXRunAlertPanel(DATE_ERROR,"Day is outside range 1 to 31","OK",NULL,NULL);
  404.         [day selectText:self];
  405.         [dow setStringValue:"XXX"];
  406.         return NO;
  407.     }
  408.     if(([month intValue]==4 || [month intValue]==6 || [month intValue]==9 || [month intValue]==11) && [day intValue]>30)
  409.     {
  410.         NXRunAlertPanel(DATE_ERROR,"Day is outside range for this month (1 to 30)","OK",NULL,NULL);
  411.         [day selectText:self];
  412.         [dow setStringValue:"XXX"];
  413.         return NO;
  414.     }
  415.     if([month intValue]==2 && ![self isItaLeapYear:[year intValue]] && [day intValue]>28)
  416.     {
  417.         NXRunAlertPanel(DATE_ERROR,"Day is outside range for this month (1 to 28). %d is not a leap year","OK",NULL,NULL,[year intValue]);
  418.         [day selectText:self];
  419.         [dow setStringValue:"XXX"];
  420.         return NO;
  421.     }
  422.     if([month intValue]==2 && [self isItaLeapYear:[year intValue]] && [day intValue]>29)
  423.     {
  424.         NXRunAlertPanel(DATE_ERROR,"Day is outside range for this month (1 to 29). %d is a leap year","OK",NULL,NULL,[year intValue]);
  425.         [day selectText:self];
  426.         [dow setStringValue:"XXX"];
  427.         return NO;
  428.     }
  429.     
  430.     
  431.     return YES;
  432. }
  433.  
  434. - initFrame:(const NXRect *)frameRect
  435. {
  436.     [super initFrame:frameRect];
  437.  
  438.     return self;
  439. }
  440.  
  441. - drawSelf:(const NXRect *)rects :(int)rectCount
  442. {
  443.     PSsetgray(NX_LTGRAY);
  444.     NXRectFill(&bounds);
  445.     return self;
  446. }
  447.  
  448. - read:(NXTypedStream *)stream
  449. {
  450.     int version;
  451.     [super read:stream];
  452.     version = NXTypedStreamClassVersion(stream, "MiscDateView");
  453.     if ( version == CURRENT_VERSION ) {
  454.         day            = NXReadObject(stream);
  455.         dayDown        = NXReadObject(stream);
  456.         dayUp        = NXReadObject(stream);
  457.         dow            = NXReadObject(stream);
  458.         month        = NXReadObject(stream);
  459.         monthDown    = NXReadObject(stream);
  460.         monthUp        = NXReadObject(stream);
  461.         year        = NXReadObject(stream);
  462.         yearDown    = NXReadObject(stream);
  463.         yearUp        = NXReadObject(stream);
  464.     } else {
  465.         [self error:"Unknown version!"];
  466.     }
  467.     return self;
  468. }
  469.  
  470. - write:(NXTypedStream *)stream
  471. {
  472.     [super write:stream];
  473.     NXWriteObject(stream, day);
  474.     NXWriteObject(stream, dayDown);
  475.     NXWriteObject(stream, dayUp);
  476.     NXWriteObject(stream, dow);
  477.     NXWriteObject(stream, month);
  478.     NXWriteObject(stream, monthDown);
  479.     NXWriteObject(stream, monthUp);
  480.     NXWriteObject(stream, year);
  481.     NXWriteObject(stream, yearDown);
  482.     NXWriteObject(stream, yearUp);
  483.     return self;
  484. }
  485.  
  486.  
  487. - (int)getDay:sender
  488. {
  489.     return [day intValue];
  490. }
  491.  
  492. - (int)getMonth:sender
  493. {
  494.     return [month intValue];
  495. }
  496.  
  497. - (int)getYear:sender
  498. {
  499.     return [year intValue];
  500. }
  501.  
  502. - day:sender
  503. {
  504.     return day;
  505. }
  506.  
  507. - month:sender
  508. {
  509.     return month;
  510. }
  511.  
  512. - year:sender
  513. {
  514.     return year;
  515. }
  516. @end
  517.